/*
 * 跳棋游戏 -- 2013-6-24
 * 作者：江潇
 * qq: 2270112418
 * Version: 0.0.1  -- 仅适用于 谷歌的 chrome 浏览器，强烈建议使用 chrome 运行、调用本次和后面推出的示例
 * 背景：学了段时间backbone框架，分析跳棋游戏比较适合于backbone的编程思维，其有多些个 collecton + model + view 模型。
 *       其实本游戏当初我不用backbone时代码量会更少，但用了结构更清晰、且易于扩展。
 *       如何应用backbone 请参见即将在iteye上连载的 《 逐行分析JS源代码 之 backbone 》[今晚将推出第一部分]，欢迎批评指正。
 *       本范例的重点在于如何计算出棋盘上每一点的坐标 及 各坐标的相互关系。
 *       后期将在分析其它源码时为本案例添加其它诸如 nodeJS 等可连网对战功能。
 *
 */! function(root)
{

    /***************************** 棋子单个可跳点模型 *************************/

    var Part = Backbone.Model.extend(
    {
        /*
         * 默认样式
         */
        defaults :
        {
            cls : 'piece part'
        },

        /*
         * 添加跳跃事件，修改其关联的棋子 Piece的coord 属性，view将监听其变化
         */
        jump : function()
        {
            this.get('referTo').jump(this.get('coord'));
        }
    });

    /*************************** 棋子单个可跳点视图 ***************************/

    var PartEl = Backbone.View.extend(
    {

        tagName : 'div',

        /*
         * 添加监听事件，当其模型删除时，视图也删除
         */
        initialize : function()
        {
            this.listenTo(this.model, 'remove', this.remove);
        },

        /*
         * 添加点击事件，点击可跳区域后，执行跳跃事件
         */
        events :
        {
            'click' : 'jump'
        },

        /*
         * 跳棋事件的入口
         */
        jump : function()
        {
            this.model.jump();
        },

        /*
         * 生成棋子所有可跳区域
         */
        render : function()
        {
            this.$el.addClass(this.model.get('cls')).addClass(this.model.get('referTo').get('color'));
            var coord = this.model.get('coord').get('coord');
            this.$el.css(
            {
                'left' : coord[0] + 20,
                'top' : coord[1] + 20
            });
            return this;
        }
    });

    /**************************** 棋子所有可跳点集合 **************************/

    var Parts = Backbone.Collection.extend(
    {

        model : Part,

        /*
         * 清空前一个棋子的可跳区域
         */
        clear : function()
        {
            while (this.length)
            {
                this.pop();
            }
        }
    });

    var parts = root.parts = new Parts;

    /*************************** 棋子模型 ***************************/

    var Piece = Backbone.Model.extend(
    {

        defaults :
        {
            cls : 'piece'
        },

        /*
         * 棋子跳跃，跳跃时先清空其可跳区域，再修改coord坐标，每次跳跃，检查是否已经成功
         */
        jump : function(coord)
        {
            parts.clear();
            this.get('coord').unset('belong');
            this.set('coord', coord);
            draughts.trigger('over', this.get('type'));
            this.collection.lastActive = this;
        },

        /*
         * 悔棋，即跳回前一次坐标
         */
        back : function()
        {
            this.jump(this._previousAttributes.coord);
        },

        /*
         * 查找附近可跳坐标
         */
        near : function()
        {
            parts.clear();
            var refer = this.get('coord').get('refer');
            for (var dir in refer )
            {
                var coord = refer[dir];
                if (!coord.get('belong'))
                {
                    //周围无棋子
                    this.getNearBy(coord);
                }
                else
                {
                    //周围有棋子，则看该子的另一侧是否有棋子
                    this.getSkip(coord, dir);
                }
            }
        },

        /*
         * 隔子查看是否有空位置
         */
        getSkip : function(coord, dir)
        {
            var refer = coord.get('refer'), _coord = refer[dir], _c;
            if (_coord && !_coord.get('belong'))
            {
                for (var i = 0, _c; _c = pieces.parts.at(i); i++)
                {
                    if (_c.get('coord').id === _coord.id)
                    {
                        return;
                    }
                }
                this.getNearBy(_coord);
                this.around(dir, _coord);
            }
        },

        /*
         * 当找到隔子跳时的处理
         */
        around : function(dir, coord)
        {
            var me = this;
            var arr = ['tl', 'tr', 'rr', 'br', 'bl', 'll'], obj =
            {
                tl : 'br',
                tr : 'bl',
                rr : 'll',
                br : 'tl',
                bl : 'tr',
                ll : 'rr'
            };
            arr.map(function(x)
            {
                if (x != dir)
                {
                }
                if (x != obj[dir])
                {
                    var refer = coord.get('refer');
                    if (refer[x] && refer[x].get('belong'))
                    {
                        me.getSkip(refer[x], x);
                    }
                }
            });
        },

        /*
         * 非隔子跳
         */
        getNearBy : function(coord)
        {
            var model = new Part(
            {
                coord : coord,
                referTo : this
            });
            parts.add(model);
            var view = new PartEl(
            {
                model : model
            });
            draughts.$el.append(view.render().el);
        }
    });

    /************************** 棋子视图 ****************************/

    var PieceEl = Backbone.View.extend(
    {
        tagName : 'div',

        /*
         * 为棋子模型添加监听事件，如果是修改了棋子的coord，则跳。remove目前是清空的时候调用
         */
        initialize : function()
        {
            this.listenTo(this.model, 'change', this.jump), this.listenTo(this.model, 'remove', this.remove);
        },

        /*
         * 棋子跳，主要是通过其coord的值，修改位置
         */
        jump : function()
        {
            this.model.get('coord').set('belong', this.model);
            var coord = this.model.get('coord').get('coord');
            this.$el.css(
            {
                'left' : coord[0] + 20,
                'top' : coord[1] + 20
            });
        },

        events :
        {
            'click' : 'choose'
        },

        choose : function()
        {
            this.model.near();
        },

        /*
         * 生成棋子视图
         */
        render : function()
        {
            this.$el.addClass(this.model.get('cls')).addClass(this.model.get('color'));
            var coord = this.model.get('coord').get('coord');
            this.$el.css(
            {
                'left' : coord[0] + 20,
                'top' : coord[1] + 20,
                'transition-duration' : '1s'
            });
            return this;
        }
    });

    /************************* 棋子集合 *****************************/

    var Pieces = Backbone.Collection.extend(
    {

        initialize : function()
        {
            this.parts = parts;
        },

        clear : function()
        {
            while (this.length)
            {
                this.pop();
            }
        },

        back : function()
        {
            this.lastActive && this.lastActive.back();
        }
    });

    var pieces = root.pieces = new Pieces;

    /************************* 棋盘上的单个点模型 *****************************/

    var Coord = Backbone.Model.extend(
    {

    });

    /************************* 棋盘上的所有点的集合 *****************************/

    var Coords = Backbone.Collection.extend(
    {
        model : Coord,

        /*
         * 这里是重点，用于计算棋盘各点的关联关系，即每个子有多少位置可跳
         */
        refer : function()
        {
            var me = this;

            me.each(function(model)
            {
                var id = model.id.split('-'), _x = id[0] - 0, _y = id[1] - 0, refers, _refer =
                {
                };
                refers =
                {
                    tl : (_x - 1) + '-' + (_y - 1),
                    tr : (_x + 1) + '-' + (_y - 1),
                    ll : (_x - 2) + '-' + _y,
                    rr : (_x + 2) + '-' + _y,
                    bl : (_x - 1) + '-' + (_y + 1),
                    br : (_x + 1) + '-' + (_y + 1)
                };
                for (var i in refers )
                {
                    var v = refers[i];
                    me.get(v) && (_refer[i] = me.get(v));
                }
                model.set('refer', _refer);
            });
        },

        clear : function()
        {
            this.map(function(coord)
            {
                coord.unset('belong');
            });
            pieces.clear();
            parts.clear();
        }
    });

    var coords = root.coords = new Coords;

    /*************************** 棋盘 ***************************/

    var Draughts = root.Draughts = Backbone.View.extend(
    {

        defaults :
        {
            width : 880,
            height : 1050,
            cls : 'board',
            color :
            {
                'A' : 'red',
                'B' : 'blue',
                'C' : 'purple',
                'D' : 'black',
                'E' : 'yellow',
                'F' : 'green'
            }
        },

        el : $('#container'),

        events :
        {
            'click #start' : 'start',
            'click #back' : 'back'
        },

        back : function()
        {
            pieces.back();
        },

        start : function()
        {
            var me = this;
            coords.clear();
            function user(players)
            {
                function create(type)
                {
                    if (!type)
                    {
                        return false;
                    }
                    var i = 1;
                    while (i++ < 11)
                    {
                        var model = new Piece(
                        {
                            type : type
                        });
                        var _coords = coords.where(
                        {
                            'type' : type
                        });
                        for (var index in _coords )
                        {
                            var _coord = _coords[index];
                            if (!_coord.get('belong'))
                            {
                                model.set('id', _coord.id);
                                model.set('coord', _coord);
                                model.set('color', me.defaults.color[type]);
                                _coord.set('belong', model);
                                break;
                            }
                        }
                        pieces.add(model);
                        var view = new PieceEl(
                        {
                            model : model
                        });
                        me.$el.append(view.render().el);
                    }
                    return true;
                }

                players = players.split('');
                while (create(players.shift()))
                {
                }

            }

            user([ '', 'A', 'AD', 'ACE', 'ABDE', 'ABCDE','ABCDEF' ][this.players = $('#player').val()]);

        },

        opposite : function(type)
        {
            var _o = ['A', 'B', 'C', 'D', 'E', 'F', 'A', 'B', 'C'];
            return coords.where(
            {
                'type' : _o[_o.indexOf(type) + [0,3,3,2,3,3,3][this.players]]
            });
        },

        initialize : function()
        {
            this.createCanvas();
            this.createCoords();
        },

        createCanvas : function()
        {
            this.canvas = $('<canvas>').attr(
            {
                'width' : this.defaults.width,
                'height' : this.defaults.height
            }).addClass(this.defaults.cls);
            this.cxt = this.canvas[0].getContext('2d');
            this.$el.append(this.canvas);
        },

        /*
         * 这里是重点，创建所有棋盘坐标
         */
        createCoords : function()
        {
            var me = this;
            var x = 430, y = 10, _lit = 720 / 24, _x, _y, _c;

            loop(true);
            loop(false);

            function loop(dir)
            {
                var j = 0, k = 0;
                while (j < 13)
                {
                    _x = x - j * _lit + k * _lit * 2;
                    if (dir)
                    {
                        _y = y + _lit * j * 2;
                        _c = 12 - j + k * 2 + '-' + j;
                    }
                    else
                    {
                        _y = y + _lit * 2 * (16 - j );
                        _c = 12 - j + k * 2 + '-' + (16 - j);
                    }
                    me.createCoord(_c, _x, _y, j, k, dir);
                    if (k == j)
                    {
                        j = k + 1;
                        k = 0;
                    }
                    else
                    {
                        k++;
                    }
                }
            }


            ['A', 'B', 'C', 'D', 'E', 'F'].map(function(c)
            {
                var models = coords.where(
                {
                    'type' : c
                });
                models.map(function(v)
                {
                    var _coord = v.get('coord');
                    me.point(_coord[0], _coord[1], me.defaults.color[c]);
                });
            });

            coords.refer();
        },

        /*
         * 这里是重点，创建单个棋盘坐标
         */
        createCoord : function(_c, _x, _y, j, k, dir)
        {
            var model =
            {
                coord : [_x, _y],
                id : _c,
                color : '#00f'
            };

            if (j < 4)
            {
                model.type = dir ? 'A' : 'D';
            }
            else if (j > 8)
            {
                if (k < j - 8)
                {
                    model.type = dir ? 'E' : 'F';
                }
                else if (k > 8)
                {
                    model.type = dir ? 'C' : 'B';
                }
            }
            coords.add(model);
            this.point(_x, _y);
        },

        point : function(x, y, color)
        {
            var cxt = this.cxt, color = color || '#0f0';
            cxt.lineWidth = 2;
            cxt.fillStyle = color;
            cxt.beginPath();
            cxt.arc(x, y, 10, 0, Math.PI * 2, true);
            cxt.closePath();
            cxt.fill();
        }
    });

    var draughts = root.draughts = new Draughts;

    /*
     * 添加监听，判断是否已经跳完
     */
    draughts.on('over', function(type)
    {
        var opposite = this.opposite(type);
        for (var i = 0, _c; _c = opposite[i]; i++)
        {
            if (!_c.get('belong') || _c.get('belong').get('type') != type)
            {
                return;
            }
        }
        alert(type + '__win!!');
    });

}(this);
